package com.example.java.base.concurrency.threadpool.factory;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * UserThreadFactory:用户自定义线程工厂(微服务下回创建多个ThreadFactory,前缀已模块命名,比如用户微服务那么就叫UserThreadFactory)</br>
 * 【强制】线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。</br>
 * 说明：Executors返回的线程池对象的弊端如下：</br>
 * 1）FixedThreadPool和SingleThreadPool：允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，从而导致OOM。</br>
 * 2）CachedThreadPool：允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量的线程，从而导致OOM。
 *
 * @author zhangxiaoxiang
 * @date 2021/04/21
 */
@Slf4j
public class UserThreadFactory implements ThreadFactory {
    private String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    /**
     * @param whatFeatureOfGroup 线程组名称(传入机房编号或者业务模块名)
     */
    public UserThreadFactory(String whatFeatureOfGroup) {
        namePrefix = "UserThreadFactoryPool-" + whatFeatureOfGroup + "-Worker-";
    }

    /**
     * 构造一个新的Thread 。 实现也可以初始化优先级，名称，守护程序状态， ThreadGroup等
     *
     * @param r 任务
     * @return 创建的线程
     */
    @Override
    public Thread newThread(Runnable r) {
        //线程全名:线程(工厂)池-线程组(机房编号或业务模块)-Worker-线程编号
        String name = namePrefix + nextId.getAndIncrement();
        //group –线程组.如果为null且存在安全管理器,则该组由SecurityManager.getThreadGroup()确定.如果没有安全管理器或SecurityManager.getThreadGroup()返回null,则该组将设置为当前线程的线程组。
        //target –启动此线程时调用run方法的对象。 如果为null ，则调用此线程的run方法。
        //name –新线程的名称
        //stackSize –新线程所需的堆栈大小，或为零以指示该参数将被忽略
        //InheritThreadLocals-如果为true ，则从构造线程继承可继承线程局部变量的初始值，否则不继承任何初始值
        //注意这是JDK9的
        Thread thread = new Thread(null, r, name, 0, false);
        log.info(thread.getName());
        return thread;
    }


}
